/*-------------------------------------------------------------------------
 *
 * pgcheckdir.c
 *
 * 一个简单的子例程，用于检查目录是否存在以及是否为空。对于 initdb 和后端都非常有用。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *		src/port/pgcheckdir.c
 *-------------------------------------------------------------------------
 */

#include "c.h"

#include <dirent.h>


/*
 * 测试一个目录是否存在且是否为空。
 *
 * 返回:
 *		0 如果不存在
 *		1 如果存在且为空
 *		2 如果存在且只包含点文件
 *		3 如果存在且包含一个挂载点
 *		4 如果存在且不为空
 *		-1 如果访问目录时出现问题（errno 反映错误）
 */
int pg_check_dir(const char *fc_dir)
{
	int			fc_result = 1;
	DIR		   *fc_chkdir;
	struct dirent *fc_file;
	bool		fc_dot_found = false;
	bool		fc_mount_found = false;
	int			fc_readdir_errno;

	fc_chkdir = opendir(fc_dir);
	if (fc_chkdir == NULL)
		return (errno == ENOENT) ? 0 : -1;

	while (errno = 0, (fc_file = readdir(fc_chkdir)) != NULL)
	{
		if (strcmp(".", fc_file->d_name) == 0 ||
			strcmp("..", fc_file->d_name) == 0)
		{
			/* 跳过此目录和父目录 */
			continue;
		}
#ifndef WIN32
		/* 文件以 "." 开头 */
		else if (fc_file->d_name[0] == '.')
		{
			fc_dot_found = true;
		}
		/* lost+found 目录 */
		else if (strcmp("lost+found", fc_file->d_name) == 0)
		{
			fc_mount_found = true;
		}
#endif
		else
		{
			fc_result = 4;			/* 不为空 */
			break;
		}
	}

	if (errno)
		fc_result = -1;			/* 某种 I/O 错误？ */

	/* 关闭 chkdir 并避免在成功时覆盖 readdir errno */
	fc_readdir_errno = errno;
	if (closedir(fc_chkdir))
		fc_result = -1;			/* 执行 closedir 时出错 */
	else
		errno = fc_readdir_errno;

	/* 如果找到 lost+found 目录，我们报告挂载点 */
	if (fc_result == 1 && fc_mount_found)
		fc_result = 3;

	/* 如果我们只找到点文件，我们报告点文件 */
	if (fc_result == 1 && fc_dot_found)
		fc_result = 2;

	return fc_result;
}
